import os, json, glob, sys
import numpy as np
import os.path as osp

"专门用于调用处理coco数据相关的脚本"
file_path = os.path.abspath(__file__)
sys.path.append(os.path.abspath(os.path.join(file_path, "..", "..", "..")))
from code_aculat.utils.xml_process import analyze_xml
from code_aculat.utils.xml_process import bbox_iou


def get_catname_to_catid():
    cat_name = ['DP1 C250ml-金罐',
                'DP10 P400ml-陈皮特饮',
                'DP11 C355ml-东鹏加气',
                'DP12 C310ml-油柑柠檬茶',
                'DP18 WATER380ml-水',
                'DP2 P250ml-金瓶',
                'DP20 C335ml-东鹏0糖',
                'DP21 P330ml-大咖',
                'DP22 P500ml-大咖',
                'DP5 P500ml-金瓶',
                'K0ANVCF00010001000 Never Coffee-咖啡饮料-拿铁咖啡-270ml',
                'K0ANVCF00020001000 Never Coffee-咖啡饮料-燕麦咖啡-270ml',
                'K0ANVCF00030001000 Never Coffee-咖啡饮料-美式咖啡-270ml',
                'K1AWXR00010001000 外星人-电解质水-荔枝海盐-电解质饮料-PET瓶-500ml',
                'K1AWXR00020001000 外星人-电解质水-青柠-电解质饮料-PET瓶-500ml',
                'K1AWXR00030001000 外星人-电解质水-西柚-电解质饮料-PET瓶-500ml',
                'K1AWXR00040001000 外星人-能量饮料-经典-能量饮料-PET瓶-350ml',
                'K1AWXR00040003000 外星人-能量饮料-经典-能量饮料-铝罐-330ml',
                'K1AWXR00050001000 外星人-能量饮料-马黛茶-能量饮料-PET瓶-350ml',
                'K1AWXR00050003000 外星人-能量饮料-马黛茶-能量饮料-铝罐-330ml',
                'K1AWXR00070001000 外星人-能量饮料-乳酸菌-能量饮料-PET瓶-350ml',
                'K1AWXR00070003000 外星人-能量饮料-乳酸菌-能量饮料-铝罐-330ml',
                'K1AWXR00080001000 外星人-能量饮料-西柚-能量饮料-PET瓶-350ml',
                'K1AWXR00080003000 外星人-能量饮料-西柚-能量饮料-铝罐-330ml',
                'K1AWXR00090001000 外星人-能量饮料-彩虹独角兽-PET瓶-350ml',
                'K1AYQSL00180001000 元气森林-元气森林-白桃-苏打气泡水-PET瓶-1250ml -福気',
                'K1AYQSL00180003000 元气森林-元气森林-白桃-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00180007000 元气森林-元气森林-白桃-苏打气泡水-铝罐-200ml',
                'K1AYQSL00190001000 元气森林-元气森林-卡曼橘-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00190005000 元气森林-元气森林-卡曼橘-苏打气泡水-铝罐-200ml',
                'K1AYQSL00210001000 元气森林-元气森林-荔枝-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00220001000 元气森林-元气森林-海盐菠萝-苏打气泡水-PET-480ml',
                'K1AYQSL00230001000 元气森林-元气森林-青瓜-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00240002000 元气森林-元气森林-乳酸菌-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00250002000 元气森林-元气森林-酸梅汁-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00260001000 元气森林-元气森林-樱花白葡萄-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00290001000 元气森林-燃茶-草莓茉莉-无糖乌龙茶-PET瓶-500ml',
                'K1AYQSL00300001000 元气森林-燃茶-醇香-无糖乌龙茶-PET瓶-500ml',
                'K1AYQSL00310001000 元气森林-燃茶-桃香-无糖乌龙茶-PET瓶-500ml',
                'K1AYQSL00320001000 元气森林-燃茶-玄米-无糖乌龙茶-PET瓶-500ml',
                'K1AYQSL00340002000 元气森林-元气森林乳茶-咖啡拿铁-乳茶-PET瓶-450ml',
                'K1AYQSL00350002000 元气森林-元气森林乳茶-茉香奶绿-乳茶-PET瓶-450ml',
                'K1AYQSL00360002000 元气森林-元气森林乳茶-浓香原味-乳茶-PET瓶-450ml',
                'K1AYQSL00410001000 元气森林-元气森林-夏黑葡萄-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00420001000 元气森林-满分-西柚-果汁微气泡-PET瓶-380ml',
                'K1AYQSL00430001000 元气森林-满分-夏黑葡萄-果汁微气泡-PET瓶-380ml',
                'K1AYQSL00440001000 元气森林-满分-王林青苹果-果汁微气泡-PET瓶-380ml',
                'K1AYQSL00450001000 元气森林-元气森林-王林青苹果-苏打气泡水-PET瓶-480ml',
                'K1AYQSL00490001000 元气森林-燃茶-焙火-无糖乌龙茶-PET瓶-500ml',
                'K1AYQSL00670001000 元气森林-元气森林-百香果-苏打气泡水-PET-480ml',
                'K1AYQSL00680001000 元气森林-元气森林-石榴红树莓-苏打气泡水-PET-480ml',
                'K1AYQSL00690001000 元气森林-纤茶-玉米须茶-PET-500ml',
                'K1AYQSL00710001000 元气森林-元气森林-红香酥梨-苏打气泡水-PET-480ml',
                'bottle',
                'row',
                '东鹏特饮维生素功能饮料罐装250毫升',
                '乐虎氨基酸维生素功能饮料瓶装380毫升',
                '健力宝运动饮料橙蜜味瓶装560毫升',
                '农夫山泉东方树叶茉莉花茶瓶装500毫升',
                '农夫山泉尖叫多肽型瓶装550毫升',
                '农夫山泉尖叫纤维型瓶装550毫升',
                '农夫山泉水溶C100柠檬味复合果汁饮料瓶装445毫升',
                '农夫山泉水溶C100西柚味复合果汁饮料瓶装445毫升',
                '农夫山泉维他命水柑橘风味瓶装500毫升',
                '农夫山泉茶π柚子绿茶瓶装500毫升',
                '农夫山泉茶π柠檬红茶瓶装500毫升',
                '农夫山泉茶π蜜桃乌龙茶瓶装500毫升',
                '农夫山泉茶π西柚茉莉花茶瓶装500毫升',
                '农夫山泉饮用天然水瓶装550毫升',
                '加多宝凉茶植物饮料瓶装550毫升',
                '加多宝凉茶植物饮料罐装310毫升',
                '可口可乐瓶装300毫升',
                '可口可乐瓶装600毫升',
                '可口可乐罐装330毫升',
                '可口可乐零度瓶装500毫升',
                '和其正凉茶瓶装550毫升',
                '娃哈哈AD钙奶瓶装450毫升',
                '娃哈哈营养快线果汁牛奶瓶装500毫升',
                '娃哈哈饮用纯净水瓶装596毫升',
                '康师傅冰糖雪梨瓶装1000毫升',
                '康师傅冰糖雪梨瓶装500毫升',
                '康师傅冰红茶柠檬口味瓶装1000毫升',
                '康师傅冰红茶柠檬口味瓶装500毫升',
                '康师傅喝开水熟水饮用水塑料瓶550毫升',
                '康师傅绿茶低糖瓶装500毫升',
                '康师傅绿茶瓶装1000毫升',
                '康师傅茉莉清茶瓶装1000毫升',
                '康师傅茉莉清茶瓶装500毫升',
                '康师傅茉莉蜜茶瓶装1000毫升',
                '康师傅茉莉蜜茶瓶装500毫升',
                '康师傅蜂蜜柚子茶瓶装500毫升',
                '康师傅酸梅汤瓶装500毫升',
                '怡宝葡萄假日瓶装440毫升',
                '怡宝饮用纯净水瓶装1555毫升',
                '怡宝饮用纯净水瓶装550毫升',
                '景田饮用纯净水瓶装560毫升',
                '王老吉凉茶植物饮料瓶装500毫升',
                '王老吉凉茶植物饮料罐装310毫升',
                '百事可乐瓶装1000毫升',
                '百事可乐瓶装1250毫升',
                '百事可乐瓶装600毫升',
                '百事可乐罐装330毫升',
                '百威淡色拉格啤酒550毫升',
                '百岁山天然矿泉水瓶装570毫升',
                '红牛罐装250毫升',
                '统一冰红茶柠檬味瓶装500毫升',
                '统一小茗同学冷泡茶青柠红茶瓶装480毫升',
                '统一海之言海盐柠檬水饮料瓶装500毫升',
                '统一绿茶低糖茉莉味瓶装500毫升',
                '统一阿萨姆原味奶茶瓶装500毫升',
                '维他柠檬茶瓶装500毫升',
                '维他柠檬茶蜜桃茶瓶装500毫升',
                '美年达橙味瓶装600毫升',
                '美汁源果粒橙瓶装1250毫升',
                '芬达橙味(扭扭瓶)瓶装500毫升',
                '达利园青梅绿茶瓶装500毫升',
                '达能脉动水蜜桃口味瓶装600毫升',
                '达能脉动菠萝口味瓶装600毫升',
                '达能脉动雪柚橘子口味瓶装600毫升',
                '达能脉动青柠口味瓶装600毫升',
                '雪碧清爽柠檬味瓶装600毫升',
                '雪碧清爽柠檬味罐装330毫升',
                '雪花8度勇闯天涯瓶装500毫升',
                '雪花8度勇闯天涯罐装500毫升',
                '青岛啤酒经典罐装500毫升', ]
    classname_to_catid = {}

    for ind in range(len(cat_name)):
        classname_to_catid[cat_name[ind]] = ind

    return classname_to_catid


def v5out_to_dict_list():
    json_path = r"/Users/edy/Downloads/best_predictions.json"
    json_path = r"/Users/edy/Desktop/yolov5/runs/test/acc_eval/best_predictions.json"
    xml_dir = r"/Users/edy/Data/yq1-0-show/yq1_0_show_data_mix_dp/dp_mix_split/foldv1/val"
    score_thresh = 0.2
    iou_thresh = 0.3

    # class_txt_path=r"/Users/edy/Data/yq1-0-show/yq1_0_show_data_mix_dp/dp_mix_split/foldv1/class_name_to_catid.txt"
    # classname_to_catid = {}  # 从txt里加载
    # with open(class_txt_path,'r') as f:
    #     records = f.readlines()
    #
    # for rec in records:
    #     cate_name, cate_id = rec.strip('\n').split('  ')
    #     classname_to_catid[cate_name]=cate_id

    classname_to_catid = get_catname_to_catid()
    target_catid = list(classname_to_catid.values())

    all_label_bbox_num = 0  # 总的目标数量
    all_pre_right_num = 0  # 总的召回目标数量
    all_pre_num = 0

    # 从json里获取推理结果
    with open(json_path, 'r') as f:
        jf = json.load(f)

    pre_img_name_list = {}

    for record in jf:
        if record['category_id'] not in target_catid:  # 从推理结果中过滤掉非目标类别的bbox
            continue

        if record['image_id'] not in pre_img_name_list:
            pre_img_name_list[record['image_id']] = []

        ob_list = record['bbox']
        ob_list.append(record['category_id'])
        ob_list.append(record['score'])  # xmin,ymin,xmax,ymax,catid,score

        pre_img_name_list[record['image_id']].append(ob_list)

    # 执行分数过滤
    pre_img_name = list(pre_img_name_list.keys())
    for img_name in pre_img_name:
        pre_img_name_list[img_name] = np.array(pre_img_name_list[img_name])
        score_save_ind = np.where(pre_img_name_list[img_name][:, -1] >= score_thresh)[0]
        if len(score_save_ind):
            pre_img_name_list[img_name] = pre_img_name_list[img_name][score_save_ind]
        else:
            del pre_img_name_list[img_name]

    # 从xml文件夹获取标注数据
    label_img_list = get_label_from_txt(xml_dir, classname_to_catid)
    label_img_name = list(label_img_list.keys())

    for img_name in label_img_name:
        if img_name in pre_img_name_list:

            matched_result = cal_iou_between_pre_label(pre_img_name_list[img_name], label_img_list[img_name],
                                                       iou_thresh)
            all_label_bbox_num += len(label_img_list[img_name])
            all_pre_num += len(pre_img_name_list[img_name])
            all_pre_right_num += len(matched_result)
        else:  # 如果推理结果里没有这个图片的推理结果，总的目标数量也要囊括这部分
            all_label_bbox_num += len(label_img_list[img_name])

    # 计算准确率指标
    acc_value = (all_pre_right_num / all_label_bbox_num) * (
                all_pre_num / (all_label_bbox_num + all_pre_num - all_pre_right_num))
    print("accuracy metric is  %f" % (acc_value))


def get_label_from_txt(xml_dir, classname_to_catid):
    "从xml文件里得到标签，用于计算指标"
    xml_files = glob.glob(osp.join(xml_dir, '*.xml'))
    img_name_list = {}

    for xml in xml_files:
        class_name, rectangle_position = analyze_xml(xml)
        target_name_idx = []

        for id in range(len(class_name)):  # 过滤掉label里的非目标类
            if class_name[id] in classname_to_catid.keys():
                target_name_idx.append(id)

        rectangle_position = np.array(rectangle_position)[target_name_idx]  # 过滤后的目标框位置
        rectangle_position = rectangle_position.tolist()

        for id in range(len(target_name_idx)):
            rectangle_position[id].append(
                classname_to_catid[class_name[target_name_idx[id]]])  # xmin,ymin,xmax,ymax,catid

        if len(target_name_idx):
            img_name = osp.basename(xml).split('.')[0]
            if img_name not in img_name_list:
                img_name_list[img_name] = rectangle_position

    return img_name_list


def cal_iou_between_pre_label(list_pre, list_label, iou_thresh=0.3):
    "计算某张图片预测结果和标签的iou，返回预测正确的bbox数量"
    arr_pre = list_pre
    arr_pre[:, 2] += arr_pre[:, 0]
    arr_pre[:, 3] += arr_pre[:, 1]
    arr_label = np.array(list_label)

    matched_result = {}
    # 得到label里有哪些catid
    label_catids = arr_label[:, -1]
    # label_catids=list(set(arr_label[:,-1]))
    pre_catids = arr_pre[:, 4]
    pre_catids = pre_catids.astype(np.int32)

    matched_label_obs_index_list = []  # 标签里被pred匹配上的目标索引

    # 将所有的pre_bbox与label_bbox求iou，达到阈值且类别一致的则认为匹配成功,iou_result.shape=(len(pre_bbox_num),len(label_bbox_num))
    iou_result = bbox_iou(arr_pre[:, :4], arr_label[:, :4])

    for label_i in range(iou_result.shape[1]):
        # 从这列里提取出满足iou_thresh的行索引
        iou_thresh_ind = np.where(iou_result[:, label_i] >= iou_thresh)[0]

        # 依次提取行索引的catid,np.where来得到与label bbox类别一样的索引
        if not len(iou_thresh_ind):
            continue
        ob_cat_id = label_catids[label_i]
        iou_thresh_pre_catids = pre_catids[iou_thresh_ind]
        iou_thresh_match = np.where(iou_thresh_pre_catids == ob_cat_id)[0]
        if not len(iou_thresh_match):
            continue

        # 取iou最大的最为匹配值
        matched_pre_ob_ind = iou_thresh_ind[iou_thresh_match[0]]
        matched_label_ob_ind = label_i

        # 得到一个预测框和label 框的一个对应关系
        if matched_pre_ob_ind in matched_result:
            continue
            # raise("the pre ob ind  %d  has matched with  %d"%(matched_pre_ob_ind,matched_result[matched_pre_ob_ind]))
        matched_result[matched_pre_ob_ind] = matched_label_ob_ind

    return matched_result

    # 从推理结果里提取对应的cat的bbox
    # for catid in label_catids:
    #     pre_ind=np.where(pre_catids==catid)[0]
    #     if len(pre_ind)<1:
    #         continue
    #
    #     label_ind=np.where(label_catids==catid)[0]
    #
    #     #计算提取出bbox与label bbox的iou
    #     pre_bboxes=np.array(arr_pre[pre_ind][:,:-1] ,dtype=np.int)
    #     label_bboxes=np.array(arr_label[label_ind],dtype=np.int)
    #     #iou_result=[pre_bbox_num,label_bbox_num]
    #     iou_result=bbox_iou(pre_bboxes[:,:4],label_bboxes[:,:4])
    #
    #     if

    # 得到提取出bbox与label_bbox的对应关系，多个都对应一个label_bbox则算预测对了一个
    # 得到该cat下的正确预测数量


v5out_to_dict_list()
